﻿import random

from simcell.cell.membrane import Membrane
from simcell.cell.protein_bag import ProteinBag

class Cell:
    """Cell class"""
    id = 0
    
    @classmethod
    def generateRandomCell(cls, num_nucleotides, g1_cycles):
        cell = Cell()
        cell.dna = Dna.generateRandomDna(num_nucleotides)
        for cicle in range(g1_cycles):
            cell.cicleG1()
    
    def __init__(self):
        Cell.id = Cell.id + 1
        self.id = Cell.id

        self.dna = Dna()
        self.cytoplasm = Cytoplasm()

    def cicleG1(self):
        """Fase G1 protein generation"""
        
        # select random start point in adn to generate a rna_m
        rna_m = self.dna.generateRnaM(ori_p)
        print rna_m
            
class CellOld:
    """Cell class"""
    id = 0
  
    def __init__(self):
        Cell.id = Cell.id + 1
        self.id = Cell.id

        self.dna = Dna()
        self.membrane  = Membrane()
        self.cytoplasm = Cytoplasm()
        

        # self.proteinBag = ProteinBag()
        
        
        self.adnCopy = ''
        self.proteinBagCopy = None
        self.freeProteinsCopy = None
        self.joinProteinsCopy = None

        self.fase = 'G1'

    def __str__(self):
        return "Cell %d" % self.id
  
    def info(self):
        txt_cell = str(self)
        txt_fase = "  Fase: %s" % self.fase
        txt_volume = "  Volumen: %d" % self.proteinBag.getVolume()
        txt_membrana = "  Membrana:"
        txt_free = "    free: [" + ", ".join(map(lambda x: str(self.membrana.freeProteins.bag[x]) + ' ' + str(x), self.membrana.freeProteins.bag)) + "]"
        txt_join = "    join: [" + ", ".join(map(lambda x: '(' + str(x[0]) + ', ' + str(x[1]) + ')', self.membrana.joinProteins)) + "]"
        txt_proteinas = "  Proteinas: " + self.proteinBag.info()
        return [txt_cell, txt_fase, txt_volume, txt_membrana, txt_free, txt_join, txt_proteinas]
    
    def cicle(self):
        if self.fase == 'G1':
            return self.cicleG1()
          
        elif self.fase == 'S':
            return self.cicleS()
          
        elif self.fase == 'G2':
            return self.cicleG2()
          
        elif self.fase == 'M':
            return self.cicleM()
      
    def cicleM(self):
        """Fase M division celular"""
        # option 1: fuerza una primera interaccion entre las celulas recien nacidas
        # option 2: dejar la celula recien nacida como citizen independiente
        #           pero en la misma posicion para que se suja por si mimsa la
        #           posible interaccion. Esto tiene la ventaja de que la recien
        #           nacida podria unirse a cualquier otra celula del citizen
        # de momento usamos la opcion 2
        cell = Cell(self.cg, self.adnCopy)
        
        for proteina, num in self.proteinBagCopy.bag.iteritems():
            cell.proteinBag.appendN(proteina, num)
        self.proteinBagCopy = None

        for proteina, num in self.freeProteinsCopy.bag.iteritems():
            cell.membrana.freeProteins.appendN(proteina, num)   
        self.freeProteinsCopy = None
        
        # TODO IMPORTANT: fix joins!!!
        # la celula opuesta no sabe que ahora esta enganchada a otra celula
        # diferente.
        cell.membrana.joinProteins = self.joinProteinsCopy
        self.joinProteinsCopy = None
            
        self.fase = 'G1'
        
        return cell
        #    print "%d -> changed to fase G1!" % self.id
    
    def cicleG2(self):
        """Fase G2 reparto de contenido"""        
        #
        # primero se reparten las proteinas del interior
        # 50% de posibilidades de que cada proteina recaiga
        # en una u otra copia de la celula
        #
        self.proteinBagCopy = ProteinBag()
        for p,v in self.proteinBag.bag.iteritems():
            for i in range(v):
                if random.random() < 0.5:
                    self.proteinBagCopy.append(p)
              
        for p,v in self.proteinBagCopy.bag.iteritems():      
            self.proteinBag.substractN(p, v)
          
        #
        # despues repartimos las proteinas libres de la membrana
        #
        self.freeProteinsCopy = ProteinBag()
        for p,v in self.membrana.freeProteins.bag.iteritems():
            for i in range(v):
                if random.random() < 0.5:
                    self.freeProteinsCopy.append(p)
              
        for p,v in self.freeProteinsCopy.bag.iteritems():    
            self.membrana.freeProteins.substractN(p, v)
        
        #
        # finalmente repartimos las proteins unidas de la membrana
        # 
        self.joinProteinsCopy = []
        for join in self.membrana.joinProteins:
            if random.random() < 0.5:
                self.joinProteinsCopy.append(join)
                self.membrana.joinProteins.remove(join)
          
    #    print "%d -> changed to fase M!" % self.id
        self.fase = 'M'
    
    def cicleS(self):
        """Fase S duplicacion del adn"""
        pos = len(self.adnCopy)
        n = self.adn[pos:pos+1]
        self.adnCopy += n
        
        if len(self.adnCopy) >= len(self.adn):
    #      print "%d -> changed to fase G2!" % self.id    
            self.fase = 'G2'
          
        return
    
    def cicleG1(self):
        """Fase G1 protein generation"""
        if self.proteinBag.getVolume() > 10000:
        #      print "%d -> changed to fase S!" % self.id
            self.fase = 'S'
            return
        
        # select random start point in adn
        start = random.randint(0, len(self.adn) - 1)
        
        # build sequence to translate
        if start == 0:
            plainSeq = self.adn
        else:
            plainSeq = self.adn[start:] + self.adn[:start-1]
            
        # break seq in codons
        seq = list(self.codons(plainSeq))
        
        # translate into codons
        aminoacidos = self.cg.translateSeq(seq)
        
        # and store it
        if not aminoacidos is None:
            proteina = "".join(aminoacidos) # plegar?
            if proteina[-1] == "-":
                self.membrana.freeProteins.append(proteina)
            else:
                self.proteinBag.append(proteina)
          
    def codons(self,seq):
        for i in xrange(0, len(seq), self.cg.lenCodon):
            yield seq[i:i + self.cg.lenCodon]